using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;

namespace PAMD.Database
{
    /// <summary>
    /// <p>Cryptography library, containing some crypting functions</p>
    /// </summary>
    public class Cryptography
    {
        #region Variables
        //Variables & initialisation
        private readonly SymmetricAlgorithm _mTdes;
        private const string StrKey = "7Wx6WryWEP0bpbZo21WR4x5yyMvrqatq";
        private const string StrVector = "k6NKyP0K4m8=";

        #endregion Variables

        #region Methods and Implementation

        /// <summary>
        /// <p>Constructor of Cryptography class with in code key and vector.</p>
        /// </summary>
        public Cryptography()
        {
            _mTdes = new TripleDESCryptoServiceProvider
                        {
                            Key = Convert.FromBase64String(StrKey),
                            IV = Convert.FromBase64String(StrVector)
                        };
        }

        /// <summary>
        /// <p>Constructor of Cryptography class.</p>
        /// </summary>
        /// <param name="key"><p>Coding cryptography key</p></param>
        /// <param name="vector"><p>Coding cryptography vector</p></param>
        public Cryptography(string key, string vector)
        {
            _mTdes = new TripleDESCryptoServiceProvider
                         {
                             Key = Convert.FromBase64String(key),
                             IV = Convert.FromBase64String(vector)
                         };
        }

        /// <summary>
        /// <p>Create a unique key based on current date.</p>
        /// </summary>
        /// <param name="longKey">Long Key.</param>
        /// <returns>String containing the key.</returns>
        public string UniqueKey(bool longKey)
        {
            Random r = new Random();
            char day;
            char[] year = new char[2];
            char minute;
            char second;

            DateTime now = DateTime.Now;

            if (now.Day < 26) day = (char)(r.Next(now.Day) + 65);
            else { day = (char)((r.Next(now.Day - 6)) + 65); }
            char month = (char)(r.Next(now.Month) + 65);
            year[0] = (char)(r.Next(int.Parse(now.Year.ToString().Substring(0, 2))) + 65);
            if ((int.Parse(now.Year.ToString().Substring(2, 2))) < 26)
            {
                year[1] = (char)(r.Next(int.Parse(now.Year.ToString().Substring(2, 2))) + 65);
            }
            else
            {
                if ((int.Parse(now.Year.ToString().Substring(2, 2))) < 53)
                {
                    year[1] = (char)((r.Next(int.Parse(now.Year.ToString().Substring(2, 2)) - 27)) + 65);
                }
                else
                    if ((int.Parse(now.Year.ToString().Substring(2, 2))) < 77)
                    {
                        year[1] = (char)((r.Next(int.Parse(now.Year.ToString().Substring(2, 2)) - 52)) + 65);
                    }
                    else
                    {
                        year[1] = (char)((r.Next(int.Parse(now.Year.ToString().Substring(2, 2)) - 79)) + 65);
                    }
            }

            char hour = (char)(now.Hour + 65);
            if (now.Minute < 26) { minute = (char)(now.Minute + 65); }
            else
            {
                if (now.Minute < 52) { minute = (char)((now.Minute - 26) + 65); }
                else { minute = (char)((now.Minute - 52) + 65); }
            }
            if (now.Second < 26) { second = (char)(now.Second + 65); }
            else
            {
                if (now.Second < 52) { second = (char)((now.Second - 26) + 65); }
                else { second = (char)((now.Second - 52) + 65); }
            }

            if (longKey)
            {
                return string.Empty + day + month + year[0] + year[1] + hour + minute + second + r.Next(now.Millisecond + 1);
            }
            return string.Empty + day + hour + minute + second + r.Next(now.Millisecond + 1);
        }

        /// <summary>
        /// <p>Symetric Crytography based on 'Data Encryption Standard'.</p> 
        /// </summary>
        /// <param name="password">Password to be crypted.</param>
        /// <param name="key">Secret key for the symetric cryptography.</param>
        /// <param name="iv">Initialisation vector for symetric alorithm.</param>
        /// <returns>An byte table</returns>
        public byte[] CryptPasswordToByte(string password, byte[] key, byte[] iv)
        {
            DES des = new DESCryptoServiceProvider();
            byte[] input = new ASCIIEncoding().GetBytes(password);

            return des.CreateEncryptor(key, iv).TransformFinalBlock(input, 0, input.Length);
        }
        /// <summary>
        /// <p>Symetric Crytography based on 'Data Encryption Standard'.</p> 
        /// </summary>
        /// <param name="password">Password to be crypted.</param>
        /// <param name="key">Secret key for the symetric cryptography.</param>
        /// <param name="iv">Initialisation vector for symetric alorithm.</param>
        /// <returns>An byte table</returns>
        public string CryptPasswordToString(string password, byte[] key, byte[] iv)
        {
            DES des = new DESCryptoServiceProvider();
            byte[] input = new ASCIIEncoding().GetBytes(password);

            return new ASCIIEncoding().GetString(des.CreateEncryptor(key, iv).TransformFinalBlock(input, 0, input.Length));
        }

        public string DeCryptString(string cryptedString)
        {
            //Variables

            ICryptoTransform ct = _mTdes.CreateDecryptor(_mTdes.Key, _mTdes.IV);
            byte[] bt = Convert.FromBase64String(cryptedString);
            MemoryStream ms = new MemoryStream();
            CryptoStream cs = new CryptoStream(ms, ct, CryptoStreamMode.Write);
            cs.Write(bt, 0, bt.Length);
            cs.FlushFinalBlock();

            cs.Close();

            return Encoding.UTF8.GetString(ms.ToArray());
        }

        public string CryptString(string nonCryptedString)
        {
            //Variables

            ICryptoTransform ct = _mTdes.CreateEncryptor(_mTdes.Key, _mTdes.IV);
            byte[] bt = Encoding.UTF8.GetBytes(nonCryptedString);
            MemoryStream ms = new MemoryStream();
            CryptoStream cs = new CryptoStream(ms, ct, CryptoStreamMode.Write);
            cs.Write(bt, 0, bt.Length);
            cs.FlushFinalBlock();

            cs.Close();

            return Convert.ToBase64String(ms.ToArray());
        }

        #endregion Methods and Implementation
    }
}
